package com.globopt.global.algorithm;

/**
 * This is helper class how to store the points, and each point in the function.
 * value
 * 
 * @author Richard Gasztany 2012.11.29.
 * 
 */
public class PointValuePair {
	private int nvars;
	private int count;
	private Point[] points;
	private double[] values;
	private int index;

	/**
	 * Init
	 * 
	 * @param count
	 *            how many points
	 * @param nvars
	 */
	public PointValuePair(int count, int nvars) {
		this.nvars = nvars;
		this.count = count;
		this.points = new Point[count];
		this.values = new double[count];
		this.index = 0;
	}

	/**
	 * Add a point per value pair.
	 * 
	 * @param point
	 * @param value
	 */
	public void add(Point point, double value) {
		points[index] = point;
		values[index] = value;
		index++;
	}

	/**
	 * Calculate the random generated coordinates function value and store.
	 * 
	 * @param fun
	 *            function
	 * @param lb
	 *            lower bound
	 * @param ub
	 *            upper bound
	 */
	public void randomFill(Function fun, double[] lb, double[] ub) {
		for (int i = 0; i < count; i++) {
			for (int j = 0; j < nvars; j++) {
				points[i] = Point.random(lb, ub);
				values[i] = fun.evaluation(points[i]);
			}
		}
	}

	/**
	 * Sorting the points. First is the minimum.
	 */
	public void sort() {
		for (int i = 0; i < count; i++) {
			int minindex = i;
			for (int j = i + 1; j < count; j++) {
				if (values[j] < values[minindex]) {
					minindex = j;
				}
			}

			double c = values[i];
			values[i] = values[minindex];
			values[minindex] = c;

			Point p = points[i];
			points[i] = points[minindex];
			points[minindex] = p;
		}
	}

	/**
	 * Give back the first gammak percent.
	 * 
	 * @param gammak
	 *            top X percent e.g. 0,3 give back the the lowest 30%
	 * @return
	 */
	public PointValuePair head(double gammak) {
		if (gammak >= 1.0) {
			return this;
		}
		int c = (int) (gammak * count);
		PointValuePair ret = new PointValuePair(c, nvars);
		for (int i = 0; i < c; i++) {
			ret.add(points[i], values[i]);
		}
		return ret;
	}

	/**
	 * @return the count
	 */
	public int getCount() {
		return count;
	}

	/**
	 * @param i
	 * @return the points
	 */
	public Point getPoints(int i) {
		return points[i];
	}

	/**
	 * @param i
	 * @return the values
	 */
	public double getValues(int i) {
		return values[i];
	}

	/**
	 * Print method
	 */
	public void print() {
		for (int i = 0; i < count; i++) {
			System.out.println("value: " + values[i] + " Point: " + points[i].toString());
		}
	}

	/**
	 * Print method
	 * 
	 * @return
	 */
	public String toString() {
		String ret = "";
		ret += "<u>Globális minimum koordinátái:</u>";
		// NumberFormat formatter = new DecimalFormat();
		// formatter = new DecimalFormat("0.#####E0");
		ret += " " + points[0].toString() + "<br><u>Függvény érték:</u>" + " " + values[0] + "<br>";

		ret += "<u>További megtalált lokális minimumok:</u><br>";
		ret += "<table border=\"1\"><tr>";
		for (int i = 1; i <= nvars; i++) {
			ret += " <th>" + i + ". koordináta </th>";
		}
		ret += "<th>Függvény érték</th> </tr>";
		for (int i = 1; i < count; i++) {
			ret += "<tr>";

			ret += points[i].toStringGlobalMin() + " <td>" + values[i] + "</td>";
			ret += "</tr>";
		}
		ret += "</table>";
		return ret;
	}
}
